package org.loong.crypto.service;

import java.security.KeyPair;

import javax.crypto.SecretKey;

import org.loong.crypto.common.exception.CryptoException;
import org.loong.crypto.core.algorithm.CipherAlgorithm;
import org.loong.crypto.core.algorithm.HmacAlgorithm;
import org.loong.crypto.core.algorithm.KeyAlgorithm;
import org.loong.crypto.core.algorithm.KeyPairAlgorithm;
import org.loong.crypto.core.algorithm.MessageDigestAlgorithm;
import org.loong.crypto.core.algorithm.SignatureAlgorithm;
import org.loong.crypto.core.params.CipherParameters;
import org.loong.crypto.core.params.HmacParameters;
import org.loong.crypto.core.params.KeyGeneratorParameters;
import org.loong.crypto.core.params.KeyPairGeneratorParameters;
import org.loong.crypto.core.params.MessageDigestParameters;
import org.loong.crypto.core.params.SignatureParameters;

/**
 * The Crypto Service.
 */
public interface CryptoService {

    /**
     * Generate random.
     * 
     * @param randomLength the random length
     * @return the random data
     * @throws the {@link CryptoException}
     */
    byte[] generateRandom(int randomLength) throws CryptoException;
    
    /**
     * Generate symmetric key.
     * 
     * @param algorithm the key algorithm
     * @param params the key generator parameters
     * @return {@link SecretKey}
     * @throws the {@link CryptoException}
     */
    SecretKey generateKey(KeyAlgorithm algorithm, KeyGeneratorParameters params) throws CryptoException;

    /**
     * Generate asymmetric key.
     * 
     * @param algorithm the key pair algorithm
     * @param params the key pair generator parameters
     * @return {@link KeyPair}
     * @throws the {@link CryptoException}
     */
    KeyPair generateKeyPair(KeyPairAlgorithm algorithm, KeyPairGeneratorParameters params) throws CryptoException;

    /**
     * Message digest.
     * 
     * @param algorithm the message digest algorithm
     * @param data the data to digest
     * @return the digest data
     * @throws the {@link CryptoException}
     */
    byte[] digest(MessageDigestAlgorithm algorithm, byte[] data) throws CryptoException;
    
    /**
     * Message digest.
     * 
     * @param algorithm the message digest algorithm
     * @param params the message digest parameters
     * @param data the data to digest
     * @return the digest data
     * @throws the {@link CryptoException}
     */
    default byte[] digest(MessageDigestAlgorithm algorithm, MessageDigestParameters params, byte[] data) throws CryptoException {
        return null;
    }

    /**
     * HMAC compute.
     * 
     * @param algorithm the hmac algorithm
     * @param params the hmac parameters
     * @param message the message to hmac
     * @return the hmac content
     * @throws the {@link CryptoException}
     */
    byte[] hmac(HmacAlgorithm algorithm, HmacParameters params, byte[] message) throws CryptoException;

    /**
     * HMAC verify.
     * 
     * @param algorithm the hmac algorithm
     * @param params the hmac parameters
     * @param message the original message
     * @param hmacToCompare the hmac to compare
     * @return the verify result
     * @throws the {@link CryptoException}
     */
    boolean verifyHmac(HmacAlgorithm algorithm, HmacParameters params, byte[] message, byte[] hmacToCompare) throws CryptoException;

    /**
     * Encrypt data.
     * 
     * @param algorithm the algorithm
     * @param params the cipher parameters
     * @param data the data to encrypt
     * @return the cipher data
     * @throws CryptoException the {@link CryptoException}
     */
    byte[] encrypt(CipherAlgorithm algorithm, CipherParameters params, byte[] data) throws CryptoException;

    /**
     * Decrypt data.
     * 
     * @param algorithm the algorithm
     * @param params the cipher parameters
     * @param cipherText the cipher text to decrypt
     * @return the plain data
     * @throws CryptoException the {@link CryptoException}
     */
    byte[] decrypt(CipherAlgorithm algorithm, CipherParameters params, byte[] cipherText) throws CryptoException;

    /**
     * Sign data.
     * 
     * @param algorithm the algorithm
     * @param params the signature parameters
     * @param data the data to sign
     * @return the signature result
     * @throws CryptoException the {@link CryptoException}
     */
    byte[] sign(SignatureAlgorithm algorithm, SignatureParameters params, byte[] data) throws CryptoException;

    /**
     * Verify signature.
     * 
     * @param algorithm the algorithm
     * @param params the signature parameters
     * @param data the signing data
     * @param signature the signature value
     * @return the verify result
     * @throws CryptoException the {@link CryptoException}
     */
    boolean verify(SignatureAlgorithm algorithm, SignatureParameters params, byte[] data, byte[] signature) throws CryptoException;
}
